/**
 * Copyright © 2015 eqxiu.com 北京中网易企秀科技有限公司 All rights reserved.
 */
package com.eqxiu.ieditor.api.controller.order;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.eqxiu.ieditor.api.controller.order.doc.NotifyDoc;
import com.eqxiu.ieditor.api.mall.IMallServiceApi;
import com.eqxiu.ieditor.api.order.IOrderServiceApi;
import com.eqxiu.ieditor.dto.Constants;
import com.eqxiu.ieditor.dto.OrderDTO;
import com.eqxiu.ieditor.dto.OrderStatusEnum;
import com.eqxiu.ieditor.dto.OrderTypeEnum;
import com.eqxiu.ieditor.msg.event.XdLogEvent;
import com.eqxiu.ieditor.msg.event.XdLogRemark;
import com.eqxiu.scene.api.SceneServiceApi;
import com.eqxiu.scene.dto.SceneDTO;

/**
 * @author ranger
 * @description 接收支付系统的异步回调
 * @update lifen
 * @date Jun 5, 2017
 */
@RestController
@RequestMapping("/api/order")
public class NotifyController implements NotifyDoc {
    @Autowired
    private IOrderServiceApi orderServiceApi;

    @Value("${payment.appid}")
    private Long paymentAppId;

    @Value("${scene.removeAd.price}")
    private Integer removeAdPrice;

    private final Logger logger = LoggerFactory.getLogger(NotifyController.class);
    @Autowired
    private ObjectMapper mapper;

    @Autowired
    private IMallServiceApi mallServiceApi;

    @Autowired
    private SceneServiceApi sceneServiceApi;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    // 实时数据价格
    private final int SCENE_DATE_IN_TIME = 5;
    // 实时数据和推送组合价格
    private final int SCENE_DATE_IN_TIME_PUSH = 8;

    /**
     * @param request
     * @return
     * @throws IOException
     * @throws JsonMappingException
     * @throws JsonParseException
     * @description 接收回调的异步通知, 消耗訂單
     * @author ranger
     * @date May 27, 2017
     * @modified by xxx 修改说明
     * @see {@link http://wiki.yqxiu.cn/pages/viewpage.action?pageId=9540199}
     */
    @RequestMapping(value = "/notify-async", method = {RequestMethod.GET, RequestMethod.POST})
    @Override
    public void handleNotify(HttpServletRequest request, HttpServletResponse resp)
            throws JsonParseException, JsonMappingException, IOException {

        String orderTradeId = request.getParameter("orderTradeId");
        String orderState = request.getParameter("orderState");

        String orderType = request.getParameter("orderType");
        String orderAmount = request.getParameter("orderAmount");
        String transactionId = request.getParameter("transactionId");
        String properties = request.getParameter("properties");
        String creater = request.getParameter("creater");
        String payOrderId = request.getParameter("orderId");
        String couponmap = request.getParameter("couponmap");

        PrintWriter writer = resp.getWriter();
        if (orderTradeId==null||creater==null){
            logger.error("notify-async error :  never find orderTradeId {} creater {}", orderTradeId,creater);
            writer.println("FAILED");
            return;
        }
        // TODO 这里应该使用redis全局锁
        List<OrderDTO> orderDto = orderServiceApi.selectByIdAndPayType(Long.valueOf(orderTradeId), creater);
        if (orderDto.isEmpty()) {
            logger.error("notify-async error :  never find order {}", payOrderId);
            writer.println("FAILED");
            return;
        }

        OrderDTO dto = orderDto.get(0);
        if ("SUCCESS".equalsIgnoreCase(orderState)) {
            dto.setTransactionId(transactionId);
            dto.setOutOrderId(payOrderId);
            dto.setCouponIds(couponmap);
            JsonNode propMap = null;
            try {
                propMap = mapper.readTree(URLDecoder.decode(properties, "utf8"));
            } catch (IOException e1) {
                e1.printStackTrace();
                dto.setRemark("properties read failed " + properties);
                dto.setStatus(OrderStatusEnum.PENDING.status());
                orderServiceApi.finishOrder(dto);
            }
            try {
                final int productId = propMap.get("productId").asInt();
                final String productName = propMap.get("productName").asText();
                final String code = propMap.get("code").asText();
                Map<String, Object> mallOrderMap = mallServiceApi.createMallOrder(payOrderId, creater, orderAmount,
                        transactionId, productName, dto.getChannel(), productId);

                if (mallOrderMap == null) {
                    logger.error("create mall order failed");
                    dto.setRemark("create mall order failed , return null");
                    dto.setStatus(OrderStatusEnum.CREATE_MALL_ORDER_FAILED.status());
                    orderServiceApi.finishOrder(dto);
                    writer.println("FAILED");
                    return;
                }

                // 保存订单到商城
                Integer mallOrderId = (Integer) mallOrderMap.get("orderId");
                Integer source = OrderApiController.determineCallbackSource(dto.getChannel(), Constants.WAP_SOURCE);

                Map<String, Object> result = mallServiceApi.createCallback(orderType, orderAmount, productId, creater,
                        mallOrderId, false, source);

                if (result == null || !result.containsKey("id")) {
                    logger.error("create mall createCallback failed, orderId: {}", orderTradeId);
                    dto.setRemark("createCallback failed , return " + result);
                    dto.setStatus(OrderStatusEnum.CREATE_MALL_CALLBACK_FAILED.status());
                    orderServiceApi.finishOrder(dto);
                    writer.println("FAILED");
                    return;
                }

                Integer asyncId = (Integer) result.get("id");
                dto.setAsyncId(asyncId);
                dto.setMallOrderId(mallOrderId);
                dto.setProductCode(code);
            } catch (Exception e) {
                logger.error("save mall order failed : {}", e.getMessage());
                writer.println("FAILED");
                dto.setRemark("createCallback failed , msg " + e.getMessage());
                dto.setStatus(OrderStatusEnum.CREATE_MALL_CALLBACK_FAILED.status());
                orderServiceApi.finishOrder(dto);
                e.printStackTrace();
                return;
            }
            dto.setStatus(OrderStatusEnum.PAID.status());
            orderServiceApi.finishOrder(dto);
            writer.println("SUCCESS");
            return;
        }
        dto.setStatus(OrderStatusEnum.PENDING.status());
        orderServiceApi.finishOrder(dto);
    }

    /**
     * @param request
     * @param resp
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws IOException
     * @description 接收充值订单的异步回调
     * @author ranger
     * @date Jul 17, 2017
     * @modified by xxx 修改说明
     */
    @RequestMapping(value = "/notify-charge-async", method = {RequestMethod.GET, RequestMethod.POST})
    @Override
    public void handleChargeNotify(HttpServletRequest request, HttpServletResponse resp)
            throws JsonParseException, JsonMappingException, IOException {

        String orderTradeId = request.getParameter("orderTradeId");
        String tradeState = request.getParameter("tradeState");
        String userId = request.getParameter("userId");

        PrintWriter writer = resp.getWriter();
        if (orderTradeId==null||userId==null){
            logger.error("notify-charge-async error :  never find orderTradeId {} userId {}", orderTradeId,userId);
            writer.println("FAILED");
            return;
        }
        List<OrderDTO> orderDto = orderServiceApi.selectByIdAndUserId(Long.valueOf(orderTradeId), userId);
        if (orderDto.isEmpty()) {
            logger.error("notify-charge-async error : never find order {}", request.getParameterMap());
            writer.println("FAILED");
            return;
        }

        OrderDTO dto = orderDto.get(0);
        if ("SUCCESS".equals(tradeState)) {
            String payOrderId = request.getParameter("id");
            dto.setOutOrderId(payOrderId);
            dto.setStatus(OrderStatusEnum.PAID.status());
            orderServiceApi.finishOrder(dto);
            writer.println("SUCCESS");
            return;
        }
        dto.setStatus(OrderStatusEnum.PENDING.status());
        orderServiceApi.finishOrder(dto);

    }

    /**
     * @param request
     * @param resp
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws IOException
     * @description 通知去尾页, 购买数据
     * @author ranger
     * @date Jul 17, 2017
     * @modified by xxx 修改说明
     */
    @RequestMapping(value = "/notify-create2", method = {RequestMethod.GET, RequestMethod.POST})
    @Override
    public void handleSceneTailerNotify(HttpServletRequest request, HttpServletResponse resp)
            throws JsonParseException, JsonMappingException, IOException {

        String orderTradeId = request.getParameter("orderTradeId");
        String orderState = request.getParameter("orderState");

        // String orderType = request.getParameter("orderType");
        String orderAmount = request.getParameter("orderAmount");
        // String transactionId = request.getParameter("transactionId");
        String properties = request.getParameter("properties");
        String creater = request.getParameter("creater");
        String payOrderId = request.getParameter("orderId");
        String couponmap = request.getParameter("couponmap");

        JsonNode propMap = null;
        try {
            propMap = mapper.readTree(URLDecoder.decode(properties, "utf8"));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        String code = null;
        if (propMap.has("code")) {
            code = propMap.get("code").asText();
        }
        Long prodId = null;
        if (propMap.has("productId")) {
            prodId = propMap.get("productId").asLong();
        }

        PrintWriter writer = resp.getWriter();
        List<OrderDTO> orderDto = orderServiceApi.selectByIdAndCode(Long.valueOf(orderTradeId), creater, code, prodId);
        if (orderDto.isEmpty()) {
            logger.error("notify-create2 error : never find order {}", request.getParameterMap());
            writer.println("FAILED");
            return;
        }

        OrderDTO dto = orderDto.get(0);
        // 判断价格是否匹配
        if (Double.valueOf(orderAmount).intValue() != dto.getTotalFee()) {
            logger.error("notify-create2 error :order {} order amount not equal orign {}, real {} ", orderTradeId, dto.getTotalFee(), orderAmount);
            writer.println("FAILED");
            dto.setStatus(OrderStatusEnum.NOTIFY_AMOUNT_NOT_MEET.status());
            orderServiceApi.finishOrder(dto);
            return;
        } else if ("SUCCESS".equals(orderState)) {
            Integer payType = dto.getPayType().intValue();
            final String eventId = dto.getId() + "";
            SceneDTO scene = sceneServiceApi.getScene(code);

            if (payType == OrderTypeEnum.REMOVE_TAIL.getState()) {
                // 校验价格
                if (removeAdPrice != -1 && removeAdPrice.equals(dto.getTotalFee())) {
                    logger.error("notify-create2 remove ad error :order {} order amount not equal orign {}, real {} ",
                            orderTradeId, removeAdPrice, dto.getTotalFee());
                    dto.setStatus(OrderStatusEnum.NOTIFY_AMOUNT_NOT_MEET.status());
                    orderServiceApi.finishOrder(dto);
                    writer.println("FAILED");
                    return;
                }
                sceneServiceApi.removeSceneTailPage(null, code);

                eventPublisher.publishEvent(new XdLogEvent(eventId, XdLogEvent.LOG_TYPE_INCOME, creater,
                        dto.getTotalFee(), creater, XdLogRemark.genXdRemark(XdLogEvent.XdBizType.WAP_TPL_IEDITOR_TAILPAGE,
                        dto.getTotalFee(), scene.getName()),
                        XdLogEvent.XdBizType.WAP_TPL_IEDITOR_TAILPAGE, scene.getId()));
            } else if (payType == OrderTypeEnum.SCENE_DATA.getState()) {
                if (dto.getTotalFee() == SCENE_DATE_IN_TIME) {
                    eventPublisher.publishEvent(new XdLogEvent(eventId, XdLogEvent.LOG_TYPE_INCOME, creater,
                            dto.getTotalFee(), creater, XdLogRemark.genXdRemark(XdLogEvent.XdBizType.WAP_TPL_IEDITOR_VIEW,
                            dto.getTotalFee(), scene.getName()),
                            XdLogEvent.XdBizType.WAP_TPL_IEDITOR_VIEW, scene.getId()));
                } else if (dto.getTotalFee() == SCENE_DATE_IN_TIME_PUSH) {
                    eventPublisher.publishEvent(new XdLogEvent(eventId, XdLogEvent.LOG_TYPE_INCOME, creater,
                            dto.getTotalFee(), creater, XdLogRemark.genXdRemark(XdLogEvent.XdBizType.WAP_TPL_IEDITOR_PUSH,
                            dto.getTotalFee(), scene.getName()),
                            XdLogEvent.XdBizType.WAP_TPL_IEDITOR_PUSH, scene.getId()));
                }

            }
            dto.setCouponIds(couponmap);
            dto.setOutOrderId(payOrderId);
            dto.setStatus(OrderStatusEnum.PAID.status());
        } else {
            dto.setStatus(OrderStatusEnum.PENDING.status());
            orderServiceApi.finishOrder(dto);
            writer.println("FAILED");
            return;
        }
        orderServiceApi.finishOrder(dto);
        writer.println("SUCCESS");
    }

}
